/*! \file
 * \brief Empty
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.1.0
 * \copyright GNU Lesser General Public License v3
 */

#include <stdint.h>

#ifndef __MYTH_CRYPTO_HPP_INCLUDED__
#define __MYTH_CRYPTO_HPP_INCLUDED__

#include "MythStream.hpp"

#if (!defined _MYTH_CRYPTO_EXTENSION_)
    #if ((!defined _MYTH_CRYPTO_STATIC_LIBRARY_) && (!defined _MYTH_CRYPTO_DYNAMIC_LIBRARY_))
        #error Please either define "_MYTH_CRYPTO_STATIC_LIBRARY_" or "_MYTH_CRYPTO_DYNAMIC_LIBRARY_"
    #endif

    #ifdef _MYTH_WINDOWS_
        #ifdef _MYTH_CRYPTO_STATIC_LIBRARY_
            #define _MYTH_CRYPTO_API_
        #endif // _MYTH_CRYPTO_STATIC_LIBRARY_

        #ifdef _MYTH_CRYPTO_DYNAMIC_LIBRARY_
            #ifdef _MYTH_CRYPTO_EXPORT_
                #define _MYTH_CRYPTO_API_ __declspec(dllexport)
            #else
                #define _MYTH_CRYPTO_API_ __declspec(dllimport)
            #endif // _MYTH_CRYPTO_EXPORT_
        #endif // _MYTH_CRYPTO_DYNAMIC_LIBRARY_
    #endif // _MYTH_WINDOWS_

    #ifdef _MYTH_LINUX_
        #define _MYTH_CRYPTO_API_
    #endif // _MYTH_LINUX_
#endif // _MYTH_CRYPTO_EXTENSION_

namespace Myth
{
namespace Crypto
{

class HashFunction;
class StreamCipher;

//! A enumeration of all the hashfunctions.
enum E_HASH_FUNCTION
{
    //! The RipeMD-128 algorithm.
    /*!
     * Flawed security, 128-bit internal state & hash size.
     */
    EHF_RIPEMD128,

    //! The RipeMD-160 algorithm.
    /*!
     * High security, 160-bit internal state & hash-size.
     */
    EHF_RIPEMD160,

    //! The RipeMD-256 algorithm.
    /*!
     * Flawed security (same as RipeMD-128), 256-bit internal state & hash-size.
     */
    EHF_RIPEMD256,

    //! The RipeMD-320 algorithm.
    /*!
     * High security (same as RipeMD-160), 320-bit internal state & hash size.
     */
    EHF_RIPEMD320,

    //! The MD5 algorithm.
    /*!
     * Flawed security, 128-bit internal state & hash size.
     */
    EHF_MD5,

    //! The SHA-1 algorithm.
    /*!
     * Reasonable security, 160-bit internal state & hash size.
     */
    EHF_SHA1,

    //! The SHA-256 algorithm.
    /*!
     * High security, 256-bit internal state & hash size.
     */
    EHF_SHA256,

    //! The SHA-224 algorithm.
    /*!
     * High security, 256-bit internal state & 224-bit hash size.
     */
    EHF_SHA224,

    //! The SHA-512 algorithm.
    /*!
     * High security, 512-bit internal state & hash size.
     */
    EHF_SHA512,

    //! The SHA-384 algorithm.
    /*!
     * High security, 512-bit internal state & 384-bit hash size.
     */
    EHF_SHA384,

    //! Not an algorithm, used to count to the total amount.
    EHF_COUNT
};

//! A enumeration of all the streamciphers.
enum E_STREAM_CIPHER
{
    //! The ARCFOUR (RC-4) algorithm.
    /*!
     * Used for example in WEP-encrypted Wifi.
     */
    ESC_ARCFOUR,
    //! Not an algorithm, used to count to the total amount.
    ESC_COUNT
};

#if (!defined _MYTH_CRYPTO_EXTENSION_)

    //! Creates a hashfunction.
    /*!
     * \return A pointer to the newly created hashfunction-object.
     * \param[in] function The type of function you want to have.
     */
    extern "C" _MYTH_CRYPTO_API_ HashFunction* _MYTH_CALL_CONV_ create_hash_function(E_HASH_FUNCTION function);

    //! Creates a streamcipher.
    /*!
     * \return A pointer to the newly created streamcipher-object.
     * \param[in] cipher The type of cipher you want to have.
     * \param[in] key A pointer to a key.
     * \param[in] key_size The length of the key in bytes.
     */
    extern "C" _MYTH_CRYPTO_API_ StreamCipher* _MYTH_CALL_CONV_ create_stream_cipher(E_STREAM_CIPHER cipher, uint8_t *key, uint32_t key_size);

#endif // _MYTH_CRYPTO_SYSTEM_EXTENSION_

//! An interface that allows the creation of cryptographical hashes.
class HashFunction : public virtual ReferenceCounter
{
public:
    //! Resets the object, it can be used again for other data.
    /// \return void
    /// \param  void
    virtual void reset(void) = 0;

    //! Feeds a new piece of data in the digester.
    /// \return void
    /// \param   uint8_t *data
    ///         Pointer to a piece of data.
    /// \param   size_t size
    ///         The size of the piece of data.
    virtual void feed(uint8_t *data, size_t size) = 0;

    //! Finishes the algorithm, no data can be fed again.
    /// \return void
    /// \param  void
    virtual void finish(void) = 0;

    //! Returns the hash.
    /// \return void
    /// \param   uint8_t *hash
    ///         A pointer to a location where you want to store the hash.
    virtual void get_hash( uint8_t *hash) = 0;

    //! Returns the hash, in hex.
    /// \return void
    /// \param   char *hash
    ///         A pointer to a location where you want to store the hash, in hex.
    virtual void get_hash_hex( char *hash) = 0;

    //! Returns the length of the hash.
    /// \return uint32_t
    ///         The length of the hash.
    /// \param  void
    virtual uint32_t  get_hash_size(void) const = 0;

    //! Returns the size of the transformation buffer.
    /// \return uint32_t
    ///         The size of the transformation buffer.
    /// \param  void
    virtual uint32_t  get_transform_size(void) const = 0;

    //! Automaticly hashes data and returns its hash.
    /// \return void
    /// \param   uint8_t *data
    ///         Pointer to a piece of data.
    /// \param   size_t bytes
    ///         The size of the block of data.
    /// \param   uint8_t *hash
    ///         A pointer to a location where you want to store the hash.
    virtual void auto_hash( uint8_t *data,
                            size_t bytes,
                            uint8_t *hash) = 0;

    //! Automaticly hashes data and returns its hash in hex-form.
    /// \return void
    /// \param   uint8_t *data
    ///         Pointer to a piece of data.
    /// \param   size_t bytes
    ///         The size of the block of data.
    /// \param   char *hash
    ///         A pointer to a location where you want to store the hash, in hex.
    virtual void auto_hash_hex( uint8_t *data,
                                size_t bytes,
                                char *hash) = 0;

    //!  Automaticly hashes a stream and returns its hash.
    /// \return void
    /// \param   Stream::Input *stream
    ///         The stream you want to hash.
    /// \param   uint32_t chunkSize
    ///         The size of the chunks that will be loaded.
    /// \param   uint8_t *hash
    ///         A pointer to a location where you want to store the hash.
    virtual void auto_hash( Stream::Input *stream,
                            uint32_t chunkSize,
                            uint8_t *hash) = 0;

    //! Automaticly hashes a stream and returns its hash in hex-form.
    /// \return void
    /// \param   Stream::Input *stream
    ///         The stream you want to hash.
    /// \param   uint32_t chunkSize
    ///         The size of the chunks that will be loaded.
    /// \param   char *hash
    ///         A pointer to a location where you want to store the hash, in hex.
    virtual void auto_hash_hex( Stream::Input *stream,
                                uint32_t chunkSize,
                                char *hash) = 0;

    //! Checks if the supplied hashes are equal.
    /// \return bool
    ///         True if the hashes are equal, false otherwise.
    /// \param   uint8_t* a
    ///         The first hash.
    /// \param   uint8_t* b
    ///         The second hash.
    virtual bool hash_equal( uint8_t* a,
                             uint8_t* b) const = 0;
};

//! An interface providing functions to allow the encryption of data.
class StreamCipher : public virtual ReferenceCounter
{
public:
    //! Initializes the algorithm with a key.
    /// \return void
    /// \param   uint8_t *key
    ///         A pointer to a block of data you want to use as a key.
    /// \param   uint16_t bytes
    ///         The length of the key.
    virtual void init( uint8_t *key,
                       uint16_t bytes) = 0;

    //! Transforms a block of data.
    /// \return void
    /// \param   uint8_t *in
    ///         A pointer to block of data you want to encode.
    /// \param   uint8_t *out
    ///         A pointer to the place you want the encoded data to be written.
    /// \param   size_t bytes
    ///         The size of the block of data.
    virtual void transform( uint8_t *in,
                            uint8_t *out,
                            size_t bytes) = 0;

    //! Skips a specified amount of data.
    /// \return void
    /// \param   size_t n
    ///         The amount you want to skip.
    virtual void skip( size_t n) = 0;
};

} // namespace Crypto
} // namespace Myth

#endif // __MYTH_CRYPTO_SYSTEM_HPP_INCLUDED__

